package sharewithus.search.solr.client;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import sharewithus.search.solr.utils.BeanDocConverter;
import sharewithus.search.solr.utils.OrderBy;
import sharewithus.search.solr.utils.Pagination;
import framelib.common.FrameCommon;

/**
 * Title:SolrClient Description:solr客户端操作类
 * 
 * @Create_by:Terry
 * @Create_date:2012-5-24
 * @Last_Edit_By:
 * @Edit_Description
 * @version:ShareWithUs 1.0
 * 
 */
public abstract class SolrClientImpl<T> implements SolrClient<T>{

	private static Logger logger = LoggerFactory.getLogger(SolrClientImpl.class);
	
	private SolrServer server;

	public SolrServer getServer() {
		return server;
	}

	@Autowired
	@Qualifier("solrServer")
	public void setServer(SolrServer server) {
		this.server = server;
	}

	protected Class<T> beanCls;

	@SuppressWarnings("unchecked")
	public SolrClientImpl() {
		beanCls = ((Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0]);
	}

	private int getStart(int pageNo, int pageSize) {
		return (pageNo - 1) * pageSize;
	}

	
	public Pagination<T> query(String queryString, int pageNo, int pageSize,
			OrderBy orderBy) {
		if (queryString == null || queryString.isEmpty())
			throw new IllegalArgumentException();
		SolrQuery query = new SolrQuery();
		query.setQuery(queryString).setStart(getStart(pageNo, pageSize))
				.setRows(pageSize);
		if (orderBy != null && orderBy.validate()) {
			for (String f : orderBy.getFields()) {
				query.addSortField(f, orderBy.getOrder());
			}
		}
		QueryResponse response = queryByParams(query);
		List<T> list = response.getBeans(beanCls);
		int totalCount = Long.valueOf(response.getResults().getNumFound())
				.intValue();
		return new Pagination<T>(pageNo, pageSize, totalCount, list);
	}

	
	public Pagination<T> query(SolrQuery query, int pageNo, int pageSize,
			OrderBy orderBy) {
		query.setStart(getStart(pageNo, pageSize)).setRows(pageSize);
		if (orderBy != null && orderBy.validate()) {
			for (String f : orderBy.getFields()) {
				query.addSortField(f, orderBy.getOrder());
			}
		}
		QueryResponse response = queryByParams(query);
		List<T> list = response.getBeans(beanCls);
		int totalCount = Long.valueOf(response.getResults().getNumFound())
				.intValue();
		return new Pagination<T>(pageNo, pageSize, totalCount, list);
	}

	protected QueryResponse queryByParams(SolrParams params) {
		QueryResponse response = null;
		try {
			response = server.query(params);
		} catch (SolrServerException e) {
			e.printStackTrace();
			return null;
		}
		return response;
	}

	/**
	 * 提交数据
	 * 
	 * @param bean
	 * @return
	 */
	public int commitBean(T bean) {
		try {
			server.addBean(bean);
			UpdateResponse rsp = server.commit(false, false);
			logger.info("Commit bean : " + bean + " to solr server");
			return rsp.getStatus();
		} catch (IOException e) {
			logger.error(e.getMessage());
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	/**
	 * 批量提交
	 * 
	 * @param beans
	 *            bean集合
	 * @return 状态值
	 */
	public int commitBeans(Collection<T> beans) {
		try {
			server.addBeans(beans);
			UpdateResponse rsp = server.commit(false, false);
			logger.info("Commit beans : " + beans.size() + " to solr server");
			return rsp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	/**
	 * 
	 * 2012-5-24, 下午4:36:34 方法描述：更新数据
	 * 
	 * @param id
	 * @param valueMap key为字段名称,value为要更新的值
	 * @return
	 */
	public int update(String id, Map<String, Object> valueMap) {
		if(id ==null || valueMap == null)
			throw new IllegalArgumentException();
		SolrQuery query = new SolrQuery(FrameCommon.SOLR_SCHEMA_KEY_NAME + ":"
				+ id);
		query.setStart(0).setRows(1);
		try {
			QueryResponse qrsp = server.query(query);
			List<T> list = qrsp.getBeans(beanCls);
			if (list == null || list.size() == 0) {
				logger.info("Document with id : " + id + " not found...");
				return -1;
			}
			T bean = list.get(0);
			for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
				BeanUtils.setProperty(bean, entry.getKey(), entry.getValue());
			}
			UpdateRequest updateRequest = new UpdateRequest();
			updateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, false,
					false);
			updateRequest.add(BeanDocConverter.bean2InputDoc(bean));
			UpdateResponse urp = updateRequest.process(server);
			return urp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IllegalAccessException e) {
			logger.error(e.getMessage());
		} catch (InvocationTargetException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	
	public int batchUpdate(Map<String, Map<String, Object>> keyMap) {
		if(keyMap == null)
			throw new IllegalArgumentException();
		StringBuffer q = new StringBuffer();
		q.append(FrameCommon.SOLR_SCHEMA_KEY_NAME+":(");
		for(Map.Entry<String, Map<String, Object>> entry : keyMap.entrySet()){
			q.append(" ").append(entry.getKey());
		}
		q.append(" )");
		System.out.println(q.toString());
		SolrQuery query = new SolrQuery(q.toString());
		query.setStart(0).setRows(keyMap.size());
		QueryResponse qrsp = null;
		try {
			qrsp = server.query(query);
			List<T> beans = qrsp.getBeans(beanCls);
			List<SolrInputDocument> inputDocs = new LinkedList<SolrInputDocument>();
			for(T bean : beans){
				String id = (String) PropertyUtils.getProperty(bean, FrameCommon.SOLR_SCHEMA_KEY_NAME);
				Map<String,Object> valueMap = keyMap.get(id);
				for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
					BeanUtils.setProperty(bean, entry.getKey(), entry.getValue());
				}
				inputDocs.add(BeanDocConverter.bean2InputDoc(bean));
			}
			UpdateRequest updateRequest = new UpdateRequest();
			updateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, false,
					false);
			updateRequest.add(inputDocs);
			UpdateResponse urp = updateRequest.process(server);
			return urp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IllegalAccessException e) {
			logger.error(e.getMessage());
		} catch (InvocationTargetException e) {
			logger.error(e.getMessage());
		} catch (NoSuchMethodException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	public int deleteById(String id) {
		try {
			server.deleteById(id);
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	public int deleteById(List<String> ids) {
		try {
			server.deleteById(ids);
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	public int deleteByQuery(String queryString) {
		try {
			server.deleteByQuery(queryString);
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	public int deleteByQuery(SolrQuery query) {
		try {
			server.deleteByQuery(query.toString());
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus();
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return -1;
	}

	public void optimize() {
		try {
			logger.info("Prepare optimize.....");
			long now = System.currentTimeMillis();
			server.optimize(true, false);
			server.optimize(false, false);
			logger.info("Complete optimization，take about：" + (System.currentTimeMillis() - now) / 1000 + "SEC");
		} catch (SolrServerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}
